package ufmg.aprendizado.ga;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import ufmg.aprendizado.classificador.Conjunto;
import ufmg.arcabouco.ga.GeneticAlgorithmGA;
import ufmg.arcabouco.ga.IndividuoGA;

public class GeneticAlgorithm extends GeneticAlgorithmGA {

	public GeneticAlgorithm(long seed) {
		super(seed);
	}

	public Random getRandom() {
		return rand;
	}

	public List<IndividuoGA> criarIndividuos() {
		List<IndividuoGA> listas = new ArrayList<IndividuoGA>();

		do {
			listas.add(new Individuo(new double[] { rand.nextDouble() * 10,
					rand.nextDouble() * 10, rand.nextDouble() * 10 }));

		} while (listas.size() != tamanhoPopulacao);

		return listas;
	}

	public void init(Conjunto conjunto, List<IndividuoGA> populacao,
			List<Integer> treino) {
		int geracao = 0;
		for (IndividuoGA ind : populacao) {
			Fitness.calcular(conjunto, ind, treino);
		}

		Collections.sort(populacao);

		while (geracao < geracoes) {

			List<IndividuoGA> aux = new ArrayList<IndividuoGA>();
			for (int i = 0; i < populacao.size() / 4; i++) {

				IndividuoGA ind1 = torneio(populacao);
				IndividuoGA ind2 = torneio(populacao);

				List<IndividuoGA> proles = operador(ind1, ind2);

				for (IndividuoGA prole : proles) {
					if (aceitacao(conjunto, prole, treino)) {
						aux.add(prole);
					}
				}
			}

			for (IndividuoGA ind : aux) {
				Fitness.calcular(conjunto, ind, treino);
			}

			List<IndividuoGA> newPopulacao = new ArrayList<IndividuoGA>();
			newPopulacao.addAll(aux);
			if (elitismo) {
				for (int i = 0; i < populacao.size() * 0.1 + 1; i++) {
					newPopulacao.add(populacao.get(0));
					populacao.remove(0);
				}
			}

			// subsituicao de regime permanente
			for (int i = newPopulacao.size(); i < populacao.size(); i++) {
				newPopulacao.add(populacao.get(i));
			}

			populacao = newPopulacao;
			for (IndividuoGA ind : populacao) {
				Fitness.calcular(conjunto, ind, treino);
			}

			Collections.sort(populacao);
			geracao++;
		}

		for (IndividuoGA ind : populacao) {
			Fitness.calcular(conjunto, ind, treino);
		}
		Collections.sort(populacao);
	}

	private boolean aceitacao(Conjunto conjunto, IndividuoGA individuo,
			List<Integer> treino) {
		Fitness.calcular(conjunto, individuo, treino);
		return individuo.getFitness() >= 0.50;
	}

}
